package cn.xiaolang.function.file_manage.io;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * <p>1. 传统的字节流读写复制</p>
 * - FileInputStream+FileOutputStream,
 * - BufferedInputStream+BufferedOutputStream -
 * <p>2.NIO系列</p>
 * - FileChannel
 * - FileChannel+buffer
 * - java.nio.Files.copy()
 * 第三方包中的FileUtils.copy方法,比如:org.apache.commons.io.FileUtils.copyFile()等等.
 * 对于单文件Files.copy的性能非常好,java的nio果然厉害.
 *
 * @author Dean
 * @date 2022-01-06
 */
@Slf4j
public enum FileCopyByteEnum implements ByteIOStream {

    FILE_IN_OUT_STREAM("FileInputStream+FileOutputStream") {
        @Override
        public void transfer(InputStream inputStream, OutputStream outputStream) {
            FileHelper.transfer(inputStream, outputStream);
        }
    },

    BUFFERED_IN_OUT_STREAM("BufferedInputStream+BufferedOutputStream") {
        @Override
        public void transfer(InputStream inputStream, OutputStream outputStream) {
            FileInputStream fileInputStream = (FileInputStream) inputStream;
            FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
            try (BufferedInputStream bufIn = new BufferedInputStream(fileInputStream);
                 BufferedOutputStream bufOut = new BufferedOutputStream(fileOutputStream);
            ) {
                FileHelper.transfer(bufIn, bufOut);
            } catch (Exception e) {
                log.error("", e);
            }
        }
    },
    /**
     * nio单线程高效率复制文件（使用文件通道FileChannel:多线程并发安全）
     */
    FILE_CHANNEL("FileChannel") {
        @Override
        public void transfer(InputStream inputStream, OutputStream outputStream) {
            FileInputStream fileInputStream = (FileInputStream) inputStream;
            FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
            try (FileChannel inChannel = fileInputStream.getChannel();
                 FileChannel outChannel = fileOutputStream.getChannel()) {
                // PS: transferTo方法只能写入最多2G的文件;所以对于大于2G的文件复制出来只有2G
                inChannel.transferTo(0, inChannel.size(), outChannel);
            } catch (IOException e) {
                log.error("", e);
            }
        }
    },

    /**
     * 增加MappedByteBuffer映射的NIO文件复制（更高效）
     */
    FILE_CHANNEL_BUFFERED("FileChannel+buffer") {
        @Override
        public void transfer(InputStream inputStream, OutputStream outputStream) {
            FileInputStream fileInputStream = (FileInputStream) inputStream;
            FileOutputStream fileOutputStream = (FileOutputStream) outputStream;
            try (FileChannel inChannel = fileInputStream.getChannel();
                 FileChannel outChannel = fileOutputStream.getChannel()) {
                MappedByteBuffer mapBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
                outChannel.write(mapBuf);
            } catch (IOException e) {
                log.error("", e);
            }
        }
    };

    @Getter
    private final String desc;

    FileCopyByteEnum(String desc) {
        this.desc = desc;
    }
}
